package com.suning.park.mp.aop;


import com.suning.park.mp.bean.Response;
import com.suning.park.mp.util.StringUtil;
import com.suning.park.mp.exception.BusinessFailException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 日志打印
 * Created by jiabin on 2016/10/8.
 */
@Aspect
@Service
public class LogServiceAop {

    private static final Logger logger = LoggerFactory.getLogger(LogServiceAop.class);

    private static Map<String, String[]> parameterNameCaches = new ConcurrentHashMap();

    private static LocalVariableTableParameterNameDiscoverer parameterNameDiscovere = new LocalVariableTableParameterNameDiscoverer();


    @Pointcut("execution(public * com.suning.park.mp.controller..*.*(..))")
    private void controller() {
    }


    @Around("controller() || @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object setControllerMDC(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            MDC.put("requestId", StringUtil.getUUID());
            printParam(pjp);
            result = pjp.proceed();
        } catch (BusinessFailException e) {
            logger.error("业务异常，错误:{}", e.getMessage());
            result = Response.FAIL(e.getMessage()).toJson();
        } catch (Exception e) {
            logger.error("未知异常", e);
            result = Response.SYSFALL().toJson();
        } finally {
            printResult(pjp, result);
            logger.info("接口耗时{}ms", System.currentTimeMillis() - startTime);
            MDC.remove("requestId");
            return result;
        }

    }


    //打印输入参数
    private void printParam(ProceedingJoinPoint point) {
        try {
            Map<String, Object> params = getParam(point);
            logger.info("目标方法:{};输入参数:{}", StringUtil.append(point.getSignature().getDeclaringTypeName(), ".", point.getSignature().getName()), params);
        } catch (Exception e) {
            logger.error("获取参数错误,错误信息:", e);
        }
    }

    //打印返回结果
    private void printResult(ProceedingJoinPoint point, Object result) {
        Class returnType = ((MethodSignature) point.getSignature()).getReturnType();
        if (StringUtil.equals(returnType.getName(), "void")) {
            return;
        }
        logger.info("返回结果:{}", result);

    }


    /**
     * 获取客户端参数
     *
     * @param point
     * @return
     * @throws NoSuchMethodException
     */
    private Map getParam(ProceedingJoinPoint point) throws NoSuchMethodException, IllegalAccessException {
        String methodLongName = point.getSignature().toLongString();
        String[] parameterNames = parameterNameCaches.get(methodLongName);
        if (parameterNames == null) {
            Method method = getMethod(point);
            parameterNames = parameterNameDiscovere.getParameterNames(method);
            parameterNameCaches.put(methodLongName, parameterNames);
        }
        Object[] args = point.getArgs();
        Map<String, Object> params = new HashMap();
        if (args.length == parameterNames.length) {
            for (int i = 0, len = args.length; i < len; i++) {
//                if (args[i] != null && TjdRequest.class.isAssignableFrom(args[i].getClass())) {
//                    Object obj = args[i];
//                    Field[] fs = args[i].getClass().getDeclaredFields();
//                    for (Field f : fs) {
//                        f.setAccessible(true); //设置些属性是可以访问的
//                        params.put(f.getName(), f.get(obj));
//                    }
//                } else {
                params.put(parameterNames[i], args[i]);
//                }
            }
        }
        return params;
    }

    /**
     * 获取当前执行的方法
     *
     * @param point
     * @return
     */
    private Method getMethod(ProceedingJoinPoint point) {
        return ((MethodSignature) point.getSignature()).getMethod();
    }

}
